/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.core.scope;

import com.inspur.edp.cef.api.scope.ICefScopeNodeParameter;
import com.inspur.edp.cef.entity.dependenceTemp.DataValidator;
import com.inspur.edp.cef.spi.scope.AbstractCefScopeExtension;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.beans.BeansException;

public abstract class CefScopeManager {

  protected CefScopeManager() {
  }

  //public static CefScopeManager Instance
  //{
  //    get
  //    {
  //        var rez = FuncSessionManager.CurrentSession.ScopeManager;
  //        if(rez == null)
  //        {
  //            FuncSessionManager.CurrentSession.ScopeManager =
  //                (rez = new CefScopeManager());
  //        }
  //        return rez;
  //    }
  //}

  /**
   * 启动Scope
   */
  public final void beginScope(String nodeId) {
    DataValidator.checkForEmptyString(nodeId, "nodeId");

    CefScopeNode tempVar = new CefScopeNode();
    tempVar.setID(nodeId);
    CefScopeNode node = tempVar;
    getScopeStack().push(node);
  }

  /**
   * 回滚
   */
  public final void setAbort(String nodeId) {
    DataValidator.checkForEmptyString(nodeId, "nodeId");

    CefScopeNode node = getScopeStack().getTopNode();
    checkNodeKey(nodeId, node.getID());
    getScopeStack().pop();
  }

  /**
   * 提交
   */
  public final void setComplete(String nodeId) {
    DataValidator.checkForEmptyString(nodeId, "nodeId");

    CefScopeNode node = getScopeStack().getTopNode();
    checkNodeKey(nodeId, node.getID());
    java.util.ArrayList<ICefScopeNodeParameter> listPara = node.getAllParameters();
    if(listPara != null && !listPara.isEmpty()) {
      ListIterator<ICefScopeNodeParameter> iterator = listPara.listIterator();
      while (iterator.hasNext()) {
        ICefScopeNodeParameter currentPar = iterator.next();
        if (currentPar.isMergableCrossType()) {
          iterateWithMergable(currentPar, iterator);
        } else {
          iterateWithUnmergable(currentPar, iterator);
        }
      }
    }
    getScopeStack().pop();
  }

  private void iterateWithUnmergable(ICefScopeNodeParameter currentPar, ListIterator<ICefScopeNodeParameter> iterator) {
    ArrayList<ICefScopeNodeParameter> suitOfPara = new ArrayList<ICefScopeNodeParameter>();
    suitOfPara.add(currentPar);
    while(iterator.hasNext()) {
      ICefScopeNodeParameter par = iterator.next();
      if(currentPar.getParameterType().equals(par.getParameterType())) {
        suitOfPara.add(par);
      } else {
        iterator.previous();
        break;
      }
    }
    excuteSetComplete(currentPar.getParameterType(), suitOfPara);
  }

  private void iterateWithMergable(ICefScopeNodeParameter currentPar, ListIterator<ICefScopeNodeParameter> iterator) {
    ArrayList<ICefScopeNodeParameter> suitOfPara = new ArrayList<ICefScopeNodeParameter>();
    suitOfPara.add(currentPar);
    while(iterator.hasNext()) {
      ICefScopeNodeParameter par = iterator.next();
      if(par.isMergableCrossType()){
        suitOfPara.add(par);
      }else{
        iterator.previous();
        break;
      }
    }

    Map<String, List<ICefScopeNodeParameter>> groups = suitOfPara.stream().collect(
        Collectors.groupingBy(item -> item.getParameterType()));
    for(Map.Entry<String, List<ICefScopeNodeParameter>> entry : groups.entrySet()) {
      excuteSetComplete(entry.getKey(), entry.getValue());
    }
  }

  /**
   * 校验nodeId是否一致
   */
  private void checkNodeKey(String nodeId, String stackNodeId) {
    if (!nodeId.equals(stackNodeId)) {
      throw new IllegalArgumentException("" + "ScopeNode结点ID不匹配。");
    }
  }

  public final void excuteSetComplete(String currentType, List<ICefScopeNodeParameter> suitOfPara)
      throws BeansException {
    AbstractCefScopeExtension extension = CefScopeExtensionManager.getInstance()
        .getScopeExtension(currentType, suitOfPara);
    extension.onSetComplete();
  }

  protected abstract CefScopeStack getScopeStack();
}
